package com.draven.redis.service;
import com.draven.redis.entity.User;
import com.draven.redis.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;



@Service
@Slf4j
public class UserService {
    @Autowired
    private UserMapper userMapper;

    /**
     * 根据用户ID获取用户信息
     * 该方法使用了缓存机制，以提高访问速度和系统性能
     * 当方法被调用时，它首先检查缓存中是否有对应的用户信息
     * 如果有，则直接返回缓存中的数据，避免了对数据库的访问
     * 如果没有，则从数据库中查询用户信息，并将结果存入缓存中
     *
     * @param id 用户ID，用于唯一标识一个用户
     * @return User对象，包含用户信息如果找不到对应的用户，则返回null
     * <p>
     * 使用@Cacheable注解实现缓存功能
     * value属性指定缓存的名称，这里使用"users"缓存
     * cacheManager属性指定使用的缓存管理器，这里使用userCacheManager
     */
    @Cacheable(value = "users", cacheManager = "userCacheManager")
    public User getUserById(Long id) {
        return userMapper.selectById(id);
    }

    /**
     * 根据用户ID查询用户信息。
     * 该方法使用了缓存机制来优化重复查询性能，但只有当查询结果非空时才会进行缓存。
     * 这样做是为了防止缓存穿透，即避免将null结果缓存起来，因为这可能意味着不存在该用户，
     * 而频繁查询不存在的用户ID会导致不必要的缓存查询开销。
     *
     * @param id 用户ID，必须是大于0的整数。
     * @return 返回一个包含用户信息的Optional对象，如果用户不存在则返回Optional.empty()。
     * <p>
     * 注意：本方法使用了自定义的缓存管理器"userCacheManager"，以适应可能的特殊缓存需求。
     * 使用"users"作为缓存名，确保相关缓存项的一致性和可管理性。
     */
    @Cacheable(value = "users", key = "'user:' + #id", unless = "#result == null", cacheManager = "userCacheManager")
    public Optional<User> findUserById(Long id) {
        // 检查传入的用户ID是否有效，如果无效则抛出异常。
        if (id == null || id <= 0) {
            throw new IllegalArgumentException("Invalid user ID");
        }
        // 使用用户ID查询数据库中的用户信息。
        User user = userMapper.selectById(id);
        // 返回查询结果，如果用户不存在，则返回Optional.empty()。
        return Optional.ofNullable(user);
    }

    /**
     * 使用注解方式更新缓存，这里需要重新查询一次是因为在更新缓存时，是将方法返回的数据写入缓存的
     * 通过此方式确保缓存中的数据是最新的
     *
     * @param user 需要更新的用户对象，包含要更新的用户信息
     * @return 返回更新后的用户对象，此对象将被写入缓存
     */
    @CachePut(value = "users", key = "'user:' + #user.id", cacheManager = "userCacheManager")
    public User updateUser(User user) {
        try {
            // 更新数据库中的用户信息
            int rowsAffected = userMapper.updateById(user);
            if (rowsAffected <= 0) {
                log.warn("Update failed for user with id: {}", user.getId());
                throw new RuntimeException("Failed to update user");
            }
            log.info("User with id {} updated successfully", user.getId());
            return user;
        } catch (Exception e) {
            log.error("Error updating user with id {}: {}", user.getId(), e.getMessage(), e);
            throw new RuntimeException("Error updating user", e);
        }
    }


        /**
         * 删除用户缓存
         * 当删除用户信息时，同时清除缓存中的用户数据，以保持数据一致性
         *
         * @param id 用户ID，用于定位要删除的用户缓存
         */
    @CacheEvict(value = "users", key = "'user:' + #id", cacheManager = "userCacheManager")
    @Transactional(rollbackFor = Exception.class)
    public void deleteUser(Long id) {
        if (id == null || id <= 0) {
            log.warn("Invalid user ID: {}", id);
            throw new IllegalArgumentException("Invalid user ID");
        }

        try {
            log.info("Deleting user with ID: {}", id);
            userMapper.deleteById(id);
            log.info("User with ID {} deleted successfully", id);
        } catch (Exception e) {
            log.error("Failed to delete user with ID {}: {}", id, e.getMessage(), e);
            throw new RuntimeException("Failed to delete user", e);
        }
    }
}




